<?php
// +----------------------------------------------------------------------
// | 统一下单接口- Native支付
// +----------------------------------------------------------------------
// | Author: @蓝优 荣誉出品
// +----------------------------------------------------------------------
class WxpayNative
{
    protected $mchid;
    protected $appid;
    protected $apiKey;
    
    public function __construct($mchid, $appid, $key)
    {
        //支付商户号
        $this->mchid = $mchid;
        //公众号APPID
        $this->appid = $appid;
        //V2 API密钥
        $this->apiKey = $key;
    }
    
    /**
     * 微信APP支付统一下单接口
     *
     * @param string $outTradeNo 商户订单号
     * @param int $totalFee 订单总金额，单位为分
     * @param string $body 商品描述
     * @param string $notifyUrl 通知地址
     * @return array 微信服务器返回的结果数组
     * @throws Exception 如果请求失败，抛出异常
     */
    public function unifiedOrder($outTradeNo, $totalFee, $body, $notifyUrl)
    {
        // 构建请求参数
        $params = $this->buildUnifiedOrderParams($outTradeNo, $totalFee, $body, $notifyUrl);
        
        // 发送请求到微信服务器
        $response = $this->sendRequestToWxpay($params);
        
        // 解析微信服务器返回的XML响应
        return $this->parseWxpayResponse($response);
    }

    /**
     * 构建微信支付统一下单接口的请求参数
     *
     * @param string $outTradeNo 商户订单号
     * @param int $totalFee 订单总金额，单位为分
     * @param string $body 商品描述
     * @param string $notifyUrl 通知地址
     * @return array 请求参数数组
     */
    protected function buildUnifiedOrderParams($outTradeNo, $totalFee, $body, $notifyUrl)
    {
        return [
            'appid' => $this->appid,
            'mch_id' => $this->mchid,
            'nonce_str' => $this->generateNonceStr(),
            'sign_type' => 'MD5',
            'body' => $body,
            'out_trade_no' => $outTradeNo,
            'total_fee' => floatval($totalFee) * 100,
            'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
            'notify_url' => $notifyUrl,
            'trade_type' => 'NATIVE',
			'product_id' => $this->generateNonceStr(8)
        ];
    }

    /**
     * 生成随机字符串
     *
     * @param int $length 字符串长度，默认为32
     * @return string 生成的随机字符串
     */
    protected function generateNonceStr($length = 32)
    {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        return substr(str_shuffle($chars), 0, $length);
    }

    /**
     * 生成签名
     *
     * @param array $params 请求参数
     * @return string 生成的签名字符串
     */
    protected function generateSign($params)
    {
        ksort($params);
        $string = '';
        foreach ($params as $key => $value) {
            if ($value != '' && !is_array($value)) {
                $string .= $key . '=' . $value . '&';
            }
        }
        $string .= 'key=' . $this->apiKey;
        return strtoupper(md5($string));
    }

    /**
     * 发送请求到微信支付服务器
     *
     * @param array $params 请求参数
     * @return string 微信服务器返回的XML响应
     * @throws Exception 如果CURL请求失败，抛出异常
     */
    protected function sendRequestToWxpay($params)
    {
        $params['sign'] = $this->generateSign($params);
        $xmlRequest = $this->arrayToXml($params);
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlRequest);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); // 启用SSL证书验证
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // 启用主机验证

        $response = curl_exec($ch);
        if ($response === false) {
            throw new Exception('CURL error: ' . curl_error($ch));
        }
        curl_close($ch);

        return $response;
    }

    /**
     * 将数组转换为XML格式
     *
     * @param array $array 要转换的数组
     * @return string 转换后的XML字符串
     */
    protected function arrayToXml($array)
    {
        $xml = "<xml>";
        foreach ($array as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<{$key}>{$val}</{$key}>";
            } else {
                $xml .= "<{$key}><![CDATA[{$val}]]></{$key}>";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

    /**
     * 解析微信支付服务器返回的XML响应
     *
     * @param string $xml 微信服务器返回的XML响应
     * @return array 解析后的响应数组
	 * @throws Exception 如果XML解析失败，抛出异常
     */
    protected function parseWxpayResponse($xml)
    {
        if (version_compare(PHP_VERSION, '8.0.0', '<')) {
            libxml_disable_entity_loader(true);
        }
        // 使用SimpleXML来解析XML字符串
        $response = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
            
        // 判断解析是否成功
        if ($response === false) {
            throw new Exception('XML parse error.');
        }
        
        // 将SimpleXML对象转换为数组，并返回
        return json_decode(json_encode($response), true);
        
    }
}
$out_trade_no = uniqid();
$appid = '你的appid';
$mch_id = '你的商户号';
$key = '你的密钥';
$wxpay = new WxpayNative($mch_id,$appid,$key);
$result = $wxpay->unifiedOrder($out_trade_no, 0.03,'支付测试', 'http://xxxx.com/notify.php');
if ($result['return_code'] == "SUCCESS" && $result['return_msg'] == "OK") {
	//$result['prepay_id']  预支付交易会话标识
	$code_url = $result['code_url'];
	include 'pay.php';
}